JSON Server 实战指南
概述
JSON Server 是一个零配置的 RESTful API 模拟服务,仅需一个 JSON 文件即可在数秒内启动一个支持完整 CRUD、过滤、分页、排序的 HTTP 服务。相比 Mock.js 的浏览器端拦截,JSON Server 提供真实的网络请求体验,适合多人协作和需要持久化数据的开发场景。
前置知识
- Mock 数据方案与工具选型
- RESTful API 设计规范(资源路径、HTTP 方法语义)
- Node.js 基础与 npm 包管理
学习目标
- 掌握 JSON Server 的 RESTful 查询能力(过滤、分页、排序、关联)
- 能够编写自定义中间件扩展服务行为
- 掌握白名单代理实现 Mock 与真实接口共存
- 理解 JSON Server 的适用边界与局限性
一、快速启动
1.1 安装与基本使用
bash
# 全局安装
npm install -g json-server
# 创建数据文件
echo '{ "posts": [{ "id": 1, "title": "Hello" }] }' > db.json
# 启动服务(默认端口 3000)
json-server --watch db.json
# 指定端口
json-server --watch db.json --port 4000启动后自动生成以下 RESTful 端点:
| 方法 | 路径 | 说明 |
|---|---|---|
| GET | /posts | 获取列表 |
| GET | /posts/1 | 获取单条 |
| POST | /posts | 新增 |
| PUT | /posts/1 | 全量更新 |
| PATCH | /posts/1 | 部分更新 |
| DELETE | /posts/1 | 删除 |
1.2 数据文件结构
json
{
"users": [
{ "id": 1, "name": "张伟", "role": "admin" },
{ "id": 2, "name": "李娜", "role": "user" }
],
"courses": [
{ "id": 1, "title": "前端工程化", "userId": 1, "price": 199 },
{ "id": 2, "title": "TypeScript 实战", "userId": 2, "price": 299 }
],
"comments": [
{ "id": 1, "body": "很好", "courseId": 1 }
]
}顶层 key 即为资源名,自动生成对应路由。
二、RESTful 查询能力
2.1 过滤
bash
# 精确匹配
GET /courses?userId=1
# 多条件
GET /courses?userId=1&price=1992.2 分页
bash
# _page: 页码(从1开始),_limit: 每页条数
GET /courses?_page=1&_limit=10
# 响应头包含分页信息
# X-Total-Count: 50
# Link: <http://localhost:3000/courses?_page=2&_limit=10>; rel="next"2.3 排序
bash
# 按 price 升序
GET /courses?_sort=price&_order=asc
# 多字段排序
GET /courses?_sort=userId,price&_order=desc,asc2.4 切片与范围
bash
# 取前 3 条
GET /courses?_start=0&_end=3
# 取第 4~6 条
GET /courses?_start=3&_limit=32.5 操作符
| 操作符 | 示例 | 说明 |
|---|---|---|
_gte / _lte | ?price_gte=100&price_lte=300 | 范围查询 |
_ne | ?role_ne=admin | 不等于 |
_like | ?title_like=前端 | 模糊匹配(正则) |
2.6 关联查询
bash
# 获取课程及其评论(_embed 嵌入子资源)
GET /courses?_embed=comments
# 获取评论及其所属课程(_expand 展开父资源)
GET /comments?_expand=course2.7 全文搜索
bash
# q 参数在所有字段中搜索
GET /courses?q=工程三、自定义中间件
JSON Server 基于 Express,支持通过中间件扩展行为。
3.1 创建自定义服务
javascript
// server.js
const jsonServer = require('json-server')
const server = jsonServer.create()
const router = jsonServer.router('db.json')
const middlewares = jsonServer.defaults()
server.use(middlewares)
// 自定义中间件:参数类型转换
server.use((req, res, next) => {
if (req.query._page) {
req.query._page = parseInt(req.query._page, 10)
}
if (req.query._limit) {
req.query._limit = parseInt(req.query._limit, 10)
}
next()
})
// 自定义中间件:CORS 增强
server.use((req, res, next) => {
res.header('Access-Control-Allow-Origin', '*')
res.header('Access-Control-Allow-Methods', 'GET,POST,PUT,PATCH,DELETE,OPTIONS')
res.header('Access-Control-Allow-Headers', 'Content-Type,Authorization')
if (req.method === 'OPTIONS') {
return res.sendStatus(204)
}
next()
})
// 自定义中间件:模拟延迟
server.use((req, res, next) => {
const delay = Math.random() * 400 + 100 // 100~500ms
setTimeout(next, delay)
})
// 自定义中间件:简单认证
server.use((req, res, next) => {
const publicPaths = ['/api/login', '/api/register']
if (publicPaths.includes(req.path)) {
return next()
}
const token = req.headers.authorization
if (!token || token !== 'Bearer mock-token') {
return res.status(401).json({ code: 401, message: 'Unauthorized' })
}
next()
})
// 自定义路由:统一响应格式
server.use('/api', (req, res, next) => {
const originalJson = res.json.bind(res)
res.json = (data) => {
return originalJson({
code: 0,
message: 'success',
data
})
}
next()
})
server.use(router)
server.listen(3000, () => {
console.log('JSON Server running at http://localhost:3000')
})3.2 启动自定义服务
bash
node server.js四、白名单代理
实际项目中,部分接口已由后端提供,需要将请求分流:
图表渲染中…
4.1 使用 http-proxy-middleware
javascript
// server.js(在自定义服务基础上添加)
const { createProxyMiddleware } = require('http-proxy-middleware')
// 白名单:这些路径代理到真实后端
const PROXY_LIST = ['/api/config', '/api/upload', '/api/payment']
PROXY_LIST.forEach((path) => {
server.use(
path,
createProxyMiddleware({
target: 'http://backend-server:8080',
changeOrigin: true
})
)
})
// 其余请求由 JSON Server 处理
server.use(router)4.2 Vite 开发代理配合
javascript
// vite.config.js
export default defineConfig({
server: {
proxy: {
'/api': {
target: 'http://localhost:3000', // JSON Server
changeOrigin: true
}
}
}
})五、静态资源服务
JSON Server 默认可托管 public/ 目录下的静态文件:
code
project/
├── db.json
├── server.js
└── public/
├── images/
│ └── avatar.png
└── files/
└── document.pdf访问 http://localhost:3000/images/avatar.png 即可获取静态资源,适合模拟文件上传后的 URL 返回。
六、路由映射
当接口路径与 JSON 数据结构不一致时,使用 routes.json 进行映射:
json
{
"/api/v1/users": "/users",
"/api/v1/courses/:id": "/courses/:id",
"/articles\\?category=:cat": "/posts?category=:cat"
}启动时指定:
bash
json-server --watch db.json --routes routes.json常见问题
| 问题 | 原因 | 解决方案 |
|---|---|---|
| 修改 db.json 后未生效 | 未使用 --watch 参数 | 添加 --watch 或重启服务 |
| POST 请求返回 201 但格式不对 | 未设置 Content-Type | 请求头添加 Content-Type: application/json |
| 关联查询返回空 | 外键命名不规范 | 确保使用 资源名单数 + Id(如 userId) |
| 并发写入数据丢失 | JSON 文件非事务性存储 | 仅用于开发环境,勿存储重要数据 |
| 自定义中间件不生效 | 注册顺序在 router 之后 | 确保中间件在 server.use(router) 之前注册 |
最佳实践
- 数据文件版本管理:将
db.json纳入 Git,团队共享统一的 Mock 数据基准 - 中间件分层:认证、日志、延迟模拟分别独立为中间件,便于按需组合
- 渐进式代理:随后端接口就绪,逐步将路径加入白名单,实现平滑切换
- 配合 Mock.js 使用:JSON Server 提供 CRUD 骨架,复杂随机数据用 Mock.js 生成后写入 db.json
- 端口约定:团队统一 JSON Server 端口(如 3001),避免与开发服务器冲突
延伸阅读
- 上一篇:Mock.js 数据生成与接口拦截
- 下一篇:平台级 Mock 工具对比与选型